package wiki.hitime.stl.daq.manager;

import com.alibaba.fastjson.JSON;
import wiki.hitime.stl.daq.bean.db.DaqCheckRule;
import wiki.hitime.stl.daq.bean.db.DaqCheckRuleHistory;
import wiki.hitime.stl.daq.bean.dto.manage.CheckRuleDTO;
import wiki.hitime.stl.daq.bean.dto.manage.MsgRuleDTO;
import wiki.hitime.stl.daq.bean.dto.req.CheckRuleGetReqDTO;
import wiki.hitime.stl.daq.bean.dto.req.CheckRuleListReqDTO;
import wiki.hitime.stl.daq.bean.dto.req.CheckRuleListAddUpdateReqDTO;
import wiki.hitime.stl.daq.enums.OperateActionEnum;
import wiki.hitime.stl.daq.exception.ServiceException;
import wiki.hitime.stl.daq.mapper.DaqCheckRuleHistoryMapper;
import wiki.hitime.stl.daq.mapper.DaqCheckRuleMapper;
import wiki.hitime.stl.daq.service.factory.DataCheckFactory;
import wiki.hitime.stl.daq.support.ContextHolder;
import wiki.hitime.stl.daq.util.UserContextUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import tk.mybatis.mapper.entity.Example;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author zhangdaoping
 * @create 2019-07-17 14:39
 */
@Service
public class DaqCheckRuleManager {

    private DaqCheckRuleMapper daqCheckRuleMapper;
    private DaqCheckRuleHistoryMapper daqCheckRuleHistoryMapper;
    private DaqMsgRuleManager daqMsgRuleManager;

    public DaqCheckRuleManager(DaqCheckRuleMapper daqCheckRuleMapper,
                               DaqCheckRuleHistoryMapper daqCheckRuleHistoryMapper,
                               DaqMsgRuleManager daqMsgRuleManager) {
        this.daqCheckRuleMapper = daqCheckRuleMapper;
        this.daqCheckRuleHistoryMapper = daqCheckRuleHistoryMapper;
        this.daqMsgRuleManager = daqMsgRuleManager;
    }

    /**
     * 加载规则集合
     *
     * @param acquisitionRuleId 采集规则编号
     * @return 规则集合
     */
    public List<DaqCheckRule> loadRuleList(Long acquisitionRuleId) {
        Example selectExample = new Example(DaqCheckRule.class, true, true);
        selectExample.createCriteria().andEqualTo("acquisitionRuleId", acquisitionRuleId).andEqualTo("isDelete", Boolean.FALSE);
        return daqCheckRuleMapper.selectByExample(selectExample);
    }

    /**
     * 添加规则
     *
     * @param checkRuleDTOList 规则DTO集合
     * @return
     */
    public void addList(Long executeRuleId, Long acquisitionRuleId, List<CheckRuleDTO> checkRuleDTOList) {
        checkRuleDTOList.stream().mapToInt(checkRuleDTO -> {
            checkRuleDTO.setExecuteRuleId(executeRuleId);
            checkRuleDTO.setAcquisitionRuleId(acquisitionRuleId);
            DaqCheckRule daqCheckRule = convertDB(checkRuleDTO);
            daqCheckRuleMapper.insertSelective(daqCheckRule);
            Long ruleId = daqCheckRule.getId();
            MsgRuleDTO msgRuleDTO = checkRuleDTO.getMsgRuleDTO();
            msgRuleDTO.setCheckRuleId(ruleId);
            msgRuleDTO.setExecuteRuleId(executeRuleId);
            daqMsgRuleManager.add(checkRuleDTO.getMsgRuleDTO());
            this.addHistory(ruleId);
            return 1;
        }).sum();
    }

    private DaqCheckRule convertDB(CheckRuleDTO checkRuleDTO) {
        DaqCheckRule daqCheckRule = DaqCheckRule.builder()
                .executeRuleId(checkRuleDTO.getExecuteRuleId())
                .acquisitionRuleId(checkRuleDTO.getAcquisitionRuleId())
                .ruleName(checkRuleDTO.getRuleName())
                .expectCheckData(checkRuleDTO.getExpectCheckData())
                .implServiceName(checkRuleDTO.getImplServiceName())
                .remark(checkRuleDTO.getRemark())
                .ctlVersion(1L)
                .createdUserId(UserContextUtil.getJobNumber())
                .createdUser(UserContextUtil.getTrueName())
                .modifiedUserId(UserContextUtil.getJobNumber())
                .modifiedUser(UserContextUtil.getTrueName())
                .build();
        DataCheckFactory checkFactory = ContextHolder.getBean(checkRuleDTO.getImplServiceName());
        Assert.notNull(checkFactory, "检查实现类为空");
        daqCheckRule.setCheckName(checkFactory.getCheckConfig().getCheckName());
        return daqCheckRule;
    }


    private void addHistory(Long ruleId) {
        DaqCheckRule daqCheckRule = daqCheckRuleMapper.selectByPrimaryKey(ruleId);
        DaqCheckRuleHistory daqCheckRuleHistory = new DaqCheckRuleHistory();
        BeanUtils.copyProperties(daqCheckRule, daqCheckRuleHistory);
        daqCheckRuleHistory.setRuleId(daqCheckRule.getId());
        daqCheckRuleHistory.setIsDelete(Boolean.FALSE);
        OperateActionEnum operateActionEnum = daqCheckRuleHistory.getCtlVersion() == 1 ? OperateActionEnum.ADD : OperateActionEnum.UPDATE;
        operateActionEnum = Boolean.TRUE.equals(daqCheckRuleHistory.getIsDelete()) ? OperateActionEnum.DELETE : operateActionEnum;
        daqCheckRuleHistory.setOperateAction(operateActionEnum.getStatus());
        daqCheckRuleHistory.setOperateData(JSON.toJSONString(daqCheckRule));
        daqCheckRuleHistoryMapper.insertSelective(daqCheckRuleHistory);
    }

    /**
     * 获取DTO
     *
     * @param reqDTO 请求实体
     * @return
     */
    public CheckRuleDTO getDTO(CheckRuleGetReqDTO reqDTO) {
        Example example = new Example(DaqCheckRule.class, true, true);
        example.createCriteria().andEqualTo("id", reqDTO.getId()).andEqualTo("isDelete", Boolean.FALSE);
        return convertDTO(daqCheckRuleMapper.selectOneByExample(example));
    }

    /**
     * 获取DTO集合
     *
     * @param reqDTO 请求实体
     * @return
     */
    public List<CheckRuleDTO> listDTO(CheckRuleListReqDTO reqDTO) {
        Example example = new Example(DaqCheckRule.class, true, true);
        example.createCriteria().andEqualTo("isDelete", Boolean.FALSE);
        Example.Criteria orCriteria = example.createCriteria();
        if (reqDTO.getExecuteRuleId() != null) {
            orCriteria.orEqualTo("executeRuleId", reqDTO.getExecuteRuleId());
        }
        if (reqDTO.getAcquisitionRuleId() != null) {
            orCriteria.orEqualTo("acquisitionRuleId", reqDTO.getAcquisitionRuleId());
        }
        example.and(orCriteria);
        return daqCheckRuleMapper.selectByExample(example).stream().map(this::convertDTO).collect(Collectors.toList());
    }

    private CheckRuleDTO convertDTO(DaqCheckRule daqCheckRule) {
        if (daqCheckRule == null) {
            return null;
        }
        CheckRuleDTO checkRuleDTO = new CheckRuleDTO();
        BeanUtils.copyProperties(daqCheckRule, checkRuleDTO);
        checkRuleDTO.setMsgRuleDTO(daqMsgRuleManager.getDTO(null, daqCheckRule.getId()));
        return checkRuleDTO;
    }

    /**
     * 修改规则
     *
     * @param reqDTO 请求实体
     * @return 修改结果，true-成功，false-失败
     */
    public Boolean updateRule(CheckRuleListAddUpdateReqDTO reqDTO) throws ServiceException {
        List<CheckRuleDTO> checkRuleDTOList = reqDTO.getCheckRuleDTOList();
        Example selectCheckExample = new Example(DaqCheckRule.class, true, true);
        selectCheckExample.createCriteria().andEqualTo("acquisitionRuleId", reqDTO.getAcquisitionRuleId()).andEqualTo("isDelete", Boolean.FALSE);
        List<DaqCheckRule> daqCheckRuleList = daqCheckRuleMapper.selectByExample(selectCheckExample);
        // 修改存在的检查规则，删除被移除的检查规则
        for (DaqCheckRule daqCheckRule : daqCheckRuleList) {
            Optional<CheckRuleDTO> filterResult = checkRuleDTOList.stream().filter(d -> d.getId() != null && d.getId().equals(daqCheckRule.getId())).findFirst();
            if (!filterResult.isPresent()) {
                this.deleteRule(daqCheckRule);
            } else {
                this.updateRule(filterResult.get());
            }
        }
        // 添加没有id的检查规则
        for (CheckRuleDTO checkRuleDTO : checkRuleDTOList) {
            if (checkRuleDTO.getId() == null) {
                this.addList(reqDTO.getExecuteRuleId(), reqDTO.getAcquisitionRuleId(), Collections.singletonList(checkRuleDTO));
            }
        }

        return true;
    }

    private void updateRule(CheckRuleDTO checkRuleDTO) throws ServiceException {
        DaqCheckRule daqRule = daqCheckRuleMapper.selectByPrimaryKey(checkRuleDTO.getId());
        if (daqRule == null) {
            throw new ServiceException("未查到待修改的检查规则");
        }
        if (!checkRuleDTO.getRuleName().equals(daqRule.getRuleName())
                || !checkRuleDTO.getImplServiceName().equals(daqRule.getImplServiceName())
                || !checkRuleDTO.getExpectCheckData().equals(daqRule.getExpectCheckData())) {
            BeanUtils.copyProperties(checkRuleDTO, daqRule);
            daqRule.setCtlVersion(daqRule.getCtlVersion() + 1);
            daqRule.setModifiedUserId(UserContextUtil.getJobNumber());
            daqRule.setModifiedUser(UserContextUtil.getTrueName());
            DataCheckFactory checkFactory = ContextHolder.getBean(checkRuleDTO.getImplServiceName());
            Assert.notNull(checkFactory, "检查实现类为空");
            daqRule.setCheckName(checkFactory.getCheckConfig().getCheckName());
            Example updateExample = new Example(DaqCheckRule.class, true, true);
            updateExample.createCriteria().andEqualTo("id", daqRule.getId()).andEqualTo("ctlVersion", daqRule.getCtlVersion() - 1);
            int count = daqCheckRuleMapper.updateByExampleSelective(daqRule, updateExample);
            if (count == 1) {
                this.addHistory(daqRule.getId());
            }
        }
    }

    private void deleteRule(DaqCheckRule daqCheckRule) {
        daqCheckRule.setCtlVersion(daqCheckRule.getCtlVersion() + 1);
        daqCheckRule.setIsDelete(Boolean.TRUE);
        daqCheckRuleMapper.updateByPrimaryKeySelective(daqCheckRule);
        this.addHistory(daqCheckRule.getId());
        daqMsgRuleManager.deleteRule(daqCheckRule.getId());
    }

    /**
     * 逻辑删除规则
     *
     * @param executeRuleId
     */
    public void delete(Long executeRuleId) {
        Example selectExample = new Example(DaqCheckRule.class, true, true);
        selectExample.createCriteria().andEqualTo("executeRuleId", executeRuleId).andEqualTo("isDelete", Boolean.FALSE);
        List<DaqCheckRule> ruleList = daqCheckRuleMapper.selectByExample(selectExample);
        Assert.notEmpty(ruleList, "检查规则为空");
        ruleList.forEach(this::deleteRule);
    }

}
